"""
Copyright 2008 Alon Zakai ('Kripken')

This code is licensed under the Apache License, version 2.0,
    http://www.apache.org/licenses/LICENSE-2.0.html


=======================================
simplefeedback
--------------
http://code.google.com/p/simplefeedback
=======================================

A simple feedback system for web pages, for Google App Engine. Example implementation
is for feedback on Doxygen documentation pages, but trivially adaptable to other
purposes. The basic idea is that at the bottom of your web pages a 'feedback' form appears,
so viewers can comment, e.g., that the page is helpful, or incomplete, etc. etc. You can
then view feedback for each page. The goal is that page-specific feedback can help you
improve the website accordingly.

A wiki would be a more extreme approach, by letting viewers also edit the page, and not
just comment on what needs fixing. This feedback system is a more 'conservative' solution
than a wiki. Each is of course suitable for different things.


Usage:

    Paste the contents of footer_fragment.html into your web pages. E.g., in Doxygen, you can
        set this as the footer, and it will be put into all generated pages (see included
        Doxyfile). In fact, this file itself is documented using Doxygen, so you can run
        Doxygen on it and see the results. The output from doxygen is included in the open
        source project, so you can also view it immediately without running Doxygen.

    Place your web pages (after the change just mentioned) under docs/html, and main.py and
        show_feedback.html in / (of your app). (Or, change the paths in this file to whatever
        you want.)

    Use the supplied app.yaml (or one like it), this will serve the html pages statically
        and the feedback pages dynamically.

    This should now work on Google App Engine.


As mentioned above, the open source project files should contain everything necessary
to work as-is, without any changes, if simply copied into a Google App Engine project
and run.

"""

from google.appengine.ext.webapp import template
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext import db


## An item of feedback about a page. Has a general category ('Adequate', 'Incomplete', etc.) and possibly
## an additional text comment.
class FeedbackItem(db.Model):
    ## The creator of this feedback comment. An ip address, username, or such (currently, just the ip)
    source = db.StringProperty()

    ## The time at which the feedback was created
    date = db.DateTimeProperty(auto_now_add=True)

    ## The title of the page to which the feedback refers (having meaningful page titles is helpful). This
    ## is used as a unique identifier of pages, so two pages with the same title will combine their feedback items.
    pagetitle = db.StringProperty()

    ## Gives a category ID given the string form (which is what appears in footer_fragment.html. These are
    ## hardcoded there, so that we can use the page statically, and not dynamically create it on every read).
    CATEGORY_IDS = { 'Helpful': 0, 'Adequate': 1, 'Incomplete': 2, 'Confusing': 3, 'Outdated': 4, 'Erroneous': 5 }

    ## Reverse lookup, return a name given an ID. Created automatically, below
    CATEGORY_NAMES = {}

    ## The category type of this feedback item
    category = db.IntegerProperty()

    ## Additional text comment attached to this feedback
    comment = db.StringProperty(multiline=True)

# Create reverse lookup for categories
for key, val in FeedbackItem.CATEGORY_IDS.iteritems():
    FeedbackItem.CATEGORY_NAMES[val] = key


## Shows the main page, which in this example implementation is assumed to be under docs/index.html
## (this is what is output from Doxygen as the main page).
class MainPage(webapp.RequestHandler):
    def get(self):
        self.redirect("docs/index.html", permanent=True)


## Handles feedback reception about a particular page - adds the feedback to the data storage
class Feedback(webapp.RequestHandler):
    def post(self):
        feedback = FeedbackItem()

        try:
            feedback.category = FeedbackItem.CATEGORY_IDS[ self.request.get('category') ] # Translate to integer ID
        except KeyError:
            feedback.category = None # Either no category was given, or an invalid one

        feedback.comment = self.request.get('comment')
        feedback.pagetitle = self.request.get('pagetitle')
        feedback.source = str(self.request.remote_addr)

        feedback.put()

        referrer = self.request.get('referrer')
        self.redirect('/thankyou?referrer='+referrer)


## Thanks the user for feedback about a particular page
class Thankyou(webapp.RequestHandler):
    def get(self):
        referrer = self.request.get('referrer')

        self.response.out.write("""
            <html><body>
                Thank you for your feedback!
                <br><br>
                <form action="%s">
                    <input type="submit" value="Back to page">
                </form>
            </body></html>
        """ % (referrer))


## Convenient to create an instance of a class to which we can add attributes at will
class DummyClass:
    pass

## Shows previous feedback about a particular page
class ShowFeedback(webapp.RequestHandler):
    def post(self):
        pagetitle = self.request.get('pagetitle')

        # Prepare category information
        categories = { }

        for ID, name in FeedbackItem.CATEGORY_NAMES.iteritems():
            category = DummyClass()
            category.name = name
            category.sum = 0

            categories[ID] = category

        # Add 'None' category
        category = DummyClass()
        category.name = "(no category)"
        category.sum = 0
        categories[None] = category

        # Go over all feedback items, creating appropriate output, and updating category summaries
        feedbacks = FeedbackItem.all().filter("pagetitle =", pagetitle).order('-date')
        output_feedbacks = []
        for feedback in feedbacks:
            output_feedback = DummyClass()
            output_feedback.source = feedback.source
            output_feedback.date = feedback.date
            output_feedback.comment = feedback.comment.split("\n") if feedback.comment != "" else None
            try:
                output_feedback.category_name = FeedbackItem.CATEGORY_NAMES[feedback.category]
            except KeyError:
                output_feedback.category_name = None

            output_feedbacks.append(output_feedback)

            categories[feedback.category].sum += 1

        template_values = {
            'pagetitle': pagetitle,
            'referrer': self.request.get('referrer'),
            'feedbacks': output_feedbacks,
            'total_feedbacks': sum([category.sum for category in categories.values()]),
            'categories': categories.values()
        }

        self.response.out.write(template.render('show_feedback.html', template_values))


###
### application/main
###

application = webapp.WSGIApplication(
    [ ('/', MainPage), ('/feedback', Feedback), ('/thankyou', Thankyou), ('/showfeedback', ShowFeedback) ]
#    ,debug=True
)

def main():
    run_wsgi_app(application)

if __name__ == "__main__":
    main()

